require "../../spec_helper"
require "../../../src/output_builder/oas3"
require "../../../src/models/endpoint"
require "../../../src/utils/utils"
require "json"

describe "OutputBuilderOas3" do
  it "print endpoints as OpenAPI 3.0 specification" do
    options = {
      "debug"   => YAML::Any.new(false),
      "verbose" => YAML::Any.new(false),
      "color"   => YAML::Any.new(false),
      "nolog"   => YAML::Any.new(false),
      "output"  => YAML::Any.new(""),
    }
    builder = OutputBuilderOas3.new(options)
    builder.set_io IO::Memory.new

    # Create endpoints with various HTTP methods and parameters
    endpoint1 = Endpoint.new("/pets/{petId}", "GET")
    endpoint1.push_param(Param.new("petId", "123", "path"))
    endpoint1.push_param(Param.new("api_key", "key123", "header"))

    endpoint2 = Endpoint.new("/pets", "POST")
    endpoint2.push_param(Param.new("name", "Fluffy", "json"))
    endpoint2.push_param(Param.new("type", "cat", "json"))
    endpoint2.push_param(Param.new("content-type", "application/json", "header"))

    endpoint3 = Endpoint.new("/pets/{petId}/photos", "POST")
    endpoint3.push_param(Param.new("petId", "123", "path"))
    endpoint3.push_param(Param.new("file", "photo.jpg", "form"))
    endpoint3.push_param(Param.new("description", "Pet photo", "form"))
    endpoint3.push_param(Param.new("session", "abc123", "cookie"))

    endpoints = [endpoint1, endpoint2, endpoint3]
    builder.print(endpoints)
    output = builder.io.to_s

    # Verify output is valid OpenAPI 3.0 spec
    spec = JSON.parse(output)

    # Check OpenAPI version
    spec["openapi"].as_s.should eq("3.0.3")

    # Check info section
    spec["info"]["title"].as_s.should eq("Generated by Noir")
    spec["info"]["version"].as_s.should eq("1.0.0")

    # Check servers section
    spec["servers"].as_a.size.should eq(1)
    spec["servers"][0]["url"].as_s.should eq("http://localhost")

    # Check paths exist and have correct structure
    paths = spec["paths"]
    paths.as_h.size.should eq(3)

    # Verify path parameter format (should be {petId} not :petId)
    paths.as_h.has_key?("/pets/{petId}").should be_true

    # Check GET endpoint with path and header parameters
    get_op = paths["/pets/{petId}"]["get"]
    get_params = get_op["parameters"].as_a
    get_params.size.should eq(2)

    # Verify path parameter has required properties with schema
    path_param = get_params.find { |p| p["in"].as_s == "path" }
    path_param.should_not be_nil
    if path_param
      path_param["name"].as_s.should eq("petId")
      path_param["required"].as_bool.should be_true
      path_param["schema"]["type"].as_s.should eq("string")
    end

    # Verify header parameter has schema
    header_param = get_params.find { |p| p["in"].as_s == "header" }
    header_param.should_not be_nil
    if header_param
      header_param["name"].as_s.should eq("api_key")
      header_param["schema"]["type"].as_s.should eq("string")
    end

    # Check response has content
    get_response = get_op["responses"]["200"]
    get_response["description"].as_s.should eq("Successful response")
    get_response["content"]["application/json"]["schema"]["type"].as_s.should eq("object")

    # Check POST endpoint with JSON body
    post_json_op = paths["/pets"]["post"]
    post_json_params = post_json_op["parameters"].as_a
    # Should have header param (JSON params go to requestBody)
    post_json_params.size.should eq(1)

    # Should have requestBody for JSON content
    post_json_op.as_h.has_key?("requestBody").should be_true
    request_body = post_json_op["requestBody"]
    request_body["content"]["application/json"]["schema"]["type"].as_s.should eq("object")
    request_body["content"]["application/json"]["schema"]["properties"].as_h.size.should eq(2)

    # Check POST endpoint with form data
    post_form_op = paths["/pets/{petId}/photos"]["post"]
    post_form_params = post_form_op["parameters"].as_a
    # Should have path param + cookie param
    post_form_params.size.should eq(2)

    # Verify cookie parameter (OAS3 supports cookies)
    cookie_param = post_form_params.find { |p| p["in"].as_s == "cookie" }
    cookie_param.should_not be_nil
    if cookie_param
      cookie_param["name"].as_s.should eq("session")
      cookie_param["schema"]["type"].as_s.should eq("string")
    end

    # Should have requestBody for form data
    post_form_op.as_h.has_key?("requestBody").should be_true
    form_body = post_form_op["requestBody"]
    form_body["content"]["application/x-www-form-urlencoded"]["schema"]["type"].as_s.should eq("object")
    form_body["content"]["application/x-www-form-urlencoded"]["schema"]["properties"].as_h.size.should eq(2)
  end
end
